package activator;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;

import library.service.Book;
import library.service.LibraryService;

public class LibraryListenerAndActivator implements BundleActivator,
		ServiceListener {

	// --- Members -------------------------------------------------------------
	private BundleContext bundleContext = null;
	private ServiceReference serviceReference = null;
	private LibraryService libraryService = null;

	private static final String FILTER = "(" + Constants.OBJECTCLASS
			+ "=library.service.LibraryService)";

	// --- Bundle Activator use-case -------------------------------------------
	public void start(BundleContext bundleContext) throws Exception {
		// 1. initialize BundleContext
		this.bundleContext = bundleContext;
		// 2. get ServiceReference
		ServiceReference srvcRef = bundleContext
				.getServiceReference(LibraryService.class.getName());
		// 3. consume Service if exists
		getLibraryService(srvcRef);
		// 4. Add ServiceListener with Filter
		this.bundleContext.addServiceListener(this, FILTER);
	}

	private void getLibraryService(ServiceReference srvcRef) {
		if (srvcRef != null) {
			libraryService = (LibraryService) bundleContext.getService(srvcRef);
		}

		if (libraryService != null) {
			// initialize ServiceReference
			serviceReference = srvcRef;

			// use the service
			Book foundBook = libraryService.findBookByName("Java");
			System.out.println("***********************");
			System.out
					.println("[ServiceEvents] FoundBook Using Library Service: "
							+ foundBook.toString());
			System.out.println("***********************");
		} else {
			System.out.println("Library Service is NULL.");
		}
	}

	public void stop(BundleContext bundleContext) throws Exception {
		// cleanup Service, ServiceReference
		if (serviceReference != null) {
			releaseResources();
		}
		// cleanup ServiceListener
		bundleContext.removeServiceListener(this);
	}

	private void releaseResources() {
		bundleContext.ungetService(serviceReference);
		serviceReference = null;
		libraryService = null;
	}

	// --- Listener use-case ---------------------------------------------------
	/**
	 * Listener method that is invoked when service event for the LibraryService
	 * is received.
	 */
	public void serviceChanged(ServiceEvent serviceEvent) {
		System.out.println("[ServiceEvents] ServiceEvent received: "
				+ serviceEvent.getServiceReference());
		switch (serviceEvent.getType()) {
		case ServiceEvent.REGISTERED: { // new LibraryService is registered
			// Get the new service only if the current serviceRef is NULL
			if (serviceReference == null) {
				getLibraryService(serviceEvent.getServiceReference());
			}
			break;
		}
		case ServiceEvent.UNREGISTERING: { // existing LibraryService is
											// unregistered
			processUnregisteringServiceEvent(serviceEvent);
			break;
		}
		case ServiceEvent.MODIFIED: {// existing LibraryService is modified
			ServiceReference tempSrvcRef = serviceEvent.getServiceReference();
			// check if it is the same service that we use
			if (serviceReference.equals(tempSrvcRef)) {
				System.out.println("[ServiceEvents] Modified Library Service");
			}
			break;
		}
		}
	}

	private void processUnregisteringServiceEvent(ServiceEvent serviceEvent) {
		ServiceReference tempSrvcRef = serviceEvent.getServiceReference();
		// check if it is the same service that we use
		if (serviceReference.equals(tempSrvcRef)) {
			System.out.println("[ServiceEvents] Ungetting Library Service");
			// 1. unget the service
			releaseResources();
			// 2. try to get a new service
			tempSrvcRef = bundleContext
					.getServiceReference(LibraryService.class.getName());
			if (tempSrvcRef != null) {
				getLibraryService(tempSrvcRef);
			}
		}
	}

}
